﻿using System;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using dtSearch.Engine;
using System.Collections;
using System.Runtime.Remoting.Messaging;
using SearchEngine;
using System.Text;

namespace DTSearchHelper
{
    public class SearchHelper
    {
        public delegate DocumentsHelper SearchDelegate(string indexPath, string SearchStatement, params string[] DefaultFields);
        public delegate void SearchFinishedDelegate(object sender, SearchHelperEventArgs e);
        public event SearchFinishedDelegate SearchFinished;


        private int maximumDocument = 1000000;
        public int MaximumDocument
        {
            get { return maximumDocument; }
            set { maximumDocument = value; }
        }

        private string noiseDataPath = "";
        public string NoiseDataPath
        {
            get { return this.noiseDataPath; }
            set { this.noiseDataPath = value; }
        }

        [ThreadStatic]
        private static Queue<string> doubleQutationQueue = new Queue<string>();

        public DocumentsHelper Search(string indexPath, string SearchStatement, params string[] DefaultFields)
        {
            string s = SearchHelper.prePare(SearchStatement,this.noiseDataPath);

            SearchJob searchJobObject = new SearchJob();
            searchJobObject.IndexesToSearch.Add(indexPath);
            searchJobObject.Request = s;
            searchJobObject.SearchFlags = searchJobObject.SearchFlags | SearchFlags.dtsSearchDelayDocInfo;
            if (maximumDocument != -1)
            {
                searchJobObject.AutoStopLimit = maximumDocument;
            }

            DateTime startTime = DateTime.Now;
            searchJobObject.Execute();
            DateTime endTime = DateTime.Now;

            JobErrorInfo jobErrors = (JobErrorInfo)searchJobObject.Errors;
            List<Exception> errors = new List<Exception>();
            for (int i = 0; i < jobErrors.Count; i++)
            {
                if ((int)jobErrors.Code(i) != 120)
                {
                    string message = (new ErrorHelper((int)jobErrors.Code(i))).Errormessage;
                    errors.Add(new Exception(message));
                }
            }

            DocumentsHelper documentsHelper = new DocumentsHelper(errors.ToArray(), searchJobObject, startTime, endTime);
            return documentsHelper;
        }

        public void BeginSearch(string indexPath, string SearchStatement, Hashtable otherInformation, params string[] DefaultFields)
        {
            SearchDelegate m = new SearchDelegate(this.Search);
            m.BeginInvoke(indexPath, SearchStatement, DefaultFields, new AsyncCallback(this.finish), otherInformation);
        }

        private void finish(IAsyncResult IAsyncRes)
        {
            if (this.SearchFinished != null)
            {
                Hashtable otherInformation = (Hashtable)IAsyncRes.AsyncState;
                AsyncResult ar = (AsyncResult)IAsyncRes;
                SearchDelegate b = (SearchDelegate)ar.AsyncDelegate;
                SearchHelperEventArgs e = new SearchHelperEventArgs(b.EndInvoke(IAsyncRes), otherInformation);
                this.SearchFinished(this, e);
            }
        }

        public static string prePare(string SearchStatement,string noiseDataPath)
        {
            string s = SearchStatement;
            s = SearchHelper.replaceArabicLetters(s);
            
            s = SearchHelper.convertToSpaces(s);
            s = SearchHelper.removeExtraSpaces(s);
            s = SearchHelper.removeNoiseData(s, noiseDataPath);
            
            //hide doubl Quotation terms
            MatchEvaluator ev = new MatchEvaluator(SearchHelper.HideDoubleQutation);
            s = Regex.Replace(s, @"""[^""]+""", ev);
            

            //unhide doubl Quotation terms
            ev = new MatchEvaluator(SearchHelper.UnHideDoubleQutation);
            s = Regex.Replace(s, "@@@@@", ev);

            return s;
        }


        //hide double qutation
        private static string HideDoubleQutation(Match m)
        {
            doubleQutationQueue.Enqueue(m.Value);
            return "@@@@@";
        }

        //unhide double qutation
        private static string UnHideDoubleQutation(Match m)
        {
            return doubleQutationQueue.Dequeue();
        }
        
        //add spaces- remove tabs and new lines-  
        private static string convertToSpaces(string statement)
        {
            string s = statement;
            s = Regex.Replace(s, @"\(", " ( ");
            s = Regex.Replace(s, @"\)", " ) ");
            s = Regex.Replace(s, @"\s", " ");// \r\n\t
            return s;
        }

        //replace arabic letters in arabic satement
        private static string replaceArabicLetters(string statement)
        {
            string s = statement;
            s = Regex.Replace(s, "[أآإ]", "ا");
            s = Regex.Replace(s, "ة", "ه");
            s = Regex.Replace(s, "ى", "ي");
            s = Regex.Replace(s, "؟", "?");
            s = Regex.Replace(s, @"[ًٌٍَُِّْ~ـ]", "");//علامات الترقيم
            s = Regex.Replace(s, @"\bوليس\b", " و ليس ");
            s = Regex.Replace(s, @"\bاوليس\b", " او ليس ");
            s = Regex.Replace(s, @"\bو\b", " AND ");
            s = Regex.Replace(s, @"\bاو\b", " OR ");
            s = Regex.Replace(s, @"\bليس\b", " NOT ");
            return s;
        }

        //remove noise Data
        public static string removeNoiseData(string statement,string noiseDataPath)
        {
            string s = statement;
            if (System.IO.File.Exists(noiseDataPath))
            {
                string[] noiseData = System.IO.File.ReadAllLines(noiseDataPath);
                for (int i = 0; i < noiseData.Length; i++)
                {
                    s = Regex.Replace(s, @"\b" + noiseData[i] + @"\b", "", RegexOptions.IgnoreCase);
                }
            }
            return s;
        }

        //doubleQuotaionStatement 
        public static string ConvertTermsToDoubleQuotaion(string statement)
        {
            string s = statement;
            //hide doubl Quotation terms
            MatchEvaluator ev = new MatchEvaluator(SearchHelper.HideDoubleQutation);
            s = Regex.Replace(s, @"""[^""]+""", ev);



            //insert double Quotation between keywords 
            s = Regex.Replace(s, @"\b", "\"");


            //remove field from double qotation
            MatchEvaluator ev2 = new MatchEvaluator(SearchHelper.removeFieldDoubleQuotation);
            s = Regex.Replace(s, @"\b\w+\s+Contains\s+", ev2,RegexOptions.IgnoreCase);



            //remove joiner from double Qutation and other settings
            s = Regex.Replace(s, @"""AND""", "AND", RegexOptions.IgnoreCase);
            s = Regex.Replace(s, @"""OR""", "OR", RegexOptions.IgnoreCase);
            s = Regex.Replace(s, @"""NOT""", "NOT", RegexOptions.IgnoreCase);
            s = Regex.Replace(s, @"""\s*""", " ");
            //s = Regex.Replace(s, @"\[\s*""", "[");
            //s = Regex.Replace(s, @"""\s*\]", "]");
            s = Regex.Replace(s, @"""\s*–\s*""", " – ");
            s = Regex.Replace(s, @"""\s*-\s*""", " - ");
            s = Regex.Replace(s, @"""\s*ـ\s*""", " ـ ");
            s = Regex.Replace(s, @"""\s*_\s*""", " _ ");

            //unhide doubl Quotation terms
            ev = new MatchEvaluator(SearchHelper.UnHideDoubleQutation);
            s = Regex.Replace(s, "@@@@@", ev);

            return s.Trim();
        }


        //remove spaces 
        private static string removeExtraSpaces(string statement)
        {
            string s = statement;
            s = Regex.Replace(s, @"\bعبد\b\s*", " عبد");
            s = Regex.Replace(s, @"\bابو\b\s*", " ابو");
            //s = Regex.Replace(s, @"\s+:", ":");
            s = Regex.Replace(s, @"\s+", " ");
            s = s.Trim();
            return s;
        }

        public static string [] getSearchFields(string IndexPath)
        {
            ListIndexJob job = new dtSearch.Engine.ListIndexJob();
            job.IndexPath = IndexPath;
            job.OutputToString = true;
            job.ListIndexFlags |= ListIndexFlags.dtsListIndexFields;
            job.Execute();
            string s = job.OutputString.Replace("\r\n", " ");
            string[] searchFields = s.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
            return searchFields;
        }


        private static string removeFieldDoubleQuotation(Match m)
        {
            string s = m.Value;
            return s.Replace(@"""", "");
        }


    }

}
